use crate::core::image_processor::{ImageIdentity, ImageProcessor};
use crate::core::storage::utils::read_dir_or_create;
use crate::error::OptionExt;
use crate::modules::config::default::ICON_CACHE_DIR;
use crate::modules::icon_manager::config::{IconManagerConfig, RuntimeIconManagerConfig};
use bincode::Encode;
use dashmap::DashSet;
use std::path::Path;
use std::sync::Arc;
use tauri::async_runtime::RwLock;
use tracing::warn;
pub mod config;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Encode, PartialEq, Eq, Serialize, Deserialize)]
pub enum IconRequest {
    /// 本地文件路径 (exe, lnk, url, ico, png) -> 提取文件图标
    Path(String),
    /// 网址 -> 下载或查找本地域名图标库
    Url(String),
    /// 文件扩展名 (.txt, .doc) -> 获取系统关联图标
    Extension(String),
}

impl IconRequest {
    pub fn get_hash_string(&self) -> String {
        let mut hasher = blake3::Hasher::new();
        let _ = bincode::encode_into_std_write(self, &mut hasher, bincode::config::standard());
        hasher.finalize().to_hex().to_string()
    }
}

#[derive(Debug)]
struct IconManagerInner {
    /// 默认的应用图标的路径
    default_app_icon_path: String,
    /// 默认的网址图片路径
    default_web_icon_path: String,
    /// 已缓存的图标哈希集合 (文件名)
    cached_icon_hashes: DashSet<String>,
    /// 要不要开启图片缓存
    enable_icon_cache: bool,
    /// 要不要联网来获取网址的图标
    enable_online: bool,
}

impl IconManagerInner {
    pub fn new(runtime_config: RuntimeIconManagerConfig) -> Self {
        let mut inner = Self {
            default_app_icon_path: runtime_config.default_app_icon_path,
            default_web_icon_path: runtime_config.default_web_icon_path,
            enable_icon_cache: true,
            enable_online: true,
            cached_icon_hashes: DashSet::new(),
        };
        inner.init();
        inner
    }

    fn init(&mut self) {
        self.cached_icon_hashes = self.scan_cached_icons();
    }

    pub fn load_from_config(&mut self, config: Arc<IconManagerConfig>) {
        self.enable_icon_cache = config.get_enable_icon_cache();
        self.enable_online = config.get_enable_online();

        if self.enable_icon_cache && self.cached_icon_hashes.is_empty() {
            self.cached_icon_hashes = self.scan_cached_icons();
        }
    }

    pub async fn get_icon(&self, request: IconRequest) -> Vec<u8> {
        let hash_name = request.get_hash_string() + ".png";

        // 1. 缓存策略
        if self.enable_icon_cache && self.cached_icon_hashes.contains(&hash_name) {
            let cached_icon_dir = ICON_CACHE_DIR.clone();
            let icon_path = Path::new(&cached_icon_dir).join(&hash_name);
            let identity = ImageIdentity::File(
                icon_path
                    .to_str()
                    .expect_programming("图标路径转换为字符串失败")
                    .to_string(),
            );
            return ImageProcessor::load_image(&identity).await;
        }

        // 2. 处理不同类型的请求
        let (mut icon_data, is_default) = match request {
            IconRequest::Path(path) => self.handle_path_request(path).await,
            IconRequest::Url(url) => self.handle_url_request(url).await,
            IconRequest::Extension(ext) => self.handle_extension_request(ext).await,
        };

        // 裁剪透明白边
        if !icon_data.is_empty() {
            if let Ok(output) = ImageProcessor::trim_transparent_white_border(icon_data.clone()) {
                icon_data = output;
            }
        }

        // 3. 写入缓存
        if self.enable_icon_cache && !is_default && !icon_data.is_empty() {
            let icon_data_clone = icon_data.clone();
            let hash_name_clone = hash_name.clone();
            tauri::async_runtime::spawn(async move {
                let cached_icon_dir = ICON_CACHE_DIR.clone();
                let icon_path = Path::new(&cached_icon_dir).join(hash_name_clone);
                let _ = tokio::fs::write(
                    icon_path
                        .to_str()
                        .expect_programming("缓存路径转换为字符串失败")
                        .to_string(),
                    icon_data_clone,
                )
                .await;
            });
            self.cached_icon_hashes.insert(hash_name);
        }

        icon_data
    }

    async fn handle_path_request(&self, path: String) -> (Vec<u8>, bool) {
        let data = ImageProcessor::load_image(&ImageIdentity::File(path)).await;
        if data.is_empty() {
            let default_data = ImageProcessor::load_image(&ImageIdentity::File(
                self.default_app_icon_path.clone(),
            ))
            .await;
            (default_data, true)
        } else {
            (data, false)
        }
    }

    async fn handle_url_request(&self, url: String) -> (Vec<u8>, bool) {
        if !self.enable_online {
            let default_data = ImageProcessor::load_image(&ImageIdentity::File(
                self.default_web_icon_path.clone(),
            ))
            .await;
            return (default_data, true);
        }

        let data = ImageProcessor::load_image(&ImageIdentity::Web(url)).await;
        if data.is_empty() {
            let default_data = ImageProcessor::load_image(&ImageIdentity::File(
                self.default_web_icon_path.clone(),
            ))
            .await;
            (default_data, true)
        } else {
            (data, false)
        }
    }

    async fn handle_extension_request(&self, ext: String) -> (Vec<u8>, bool) {
        let data = ImageProcessor::load_image(&ImageIdentity::Extension(ext)).await;
        if data.is_empty() {
            let default_data = ImageProcessor::load_image(&ImageIdentity::File(
                self.default_app_icon_path.clone(),
            ))
            .await;
            (default_data, true)
        } else {
            (data, false)
        }
    }

    fn scan_cached_icons(&self) -> DashSet<String> {
        let result = DashSet::new();
        if !self.enable_icon_cache {
            return result;
        }

        let icon_cache_dir_clone = ICON_CACHE_DIR.clone();
        match read_dir_or_create(icon_cache_dir_clone) {
            Ok(entries) => {
                for entry in entries.flatten() {
                    let file_name = entry.file_name();
                    let file_name = file_name.to_string_lossy();
                    result.insert(file_name.into_owned());
                }
            }
            Err(e) => warn!("Error reading icon cache directory: {}", e),
        }
        result
    }

    pub async fn get_everything_icon(&self, path: String) -> Vec<u8> {
        let path_lower = path.to_lowercase();

        // 1. Executables/Links/URLs -> Direct load, no cache
        if path_lower.ends_with(".exe")
            || path_lower.ends_with(".lnk")
            || path_lower.ends_with(".url")
        {
            return ImageProcessor::load_image(&ImageIdentity::File(path)).await;
        }

        // 2. Images -> Direct load, resize if needed
        let image_extensions = [
            ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".tiff", ".tif", ".svg",
        ];
        if image_extensions.iter().any(|ext| path_lower.ends_with(ext)) {
            let data = ImageProcessor::load_image(&ImageIdentity::File(path)).await;
            if !data.is_empty() {
                if let Ok(resized) = ImageProcessor::resize_image(data.clone(), 256, 256).await {
                    return resized;
                }
            }
            return data;
        }

        // 3. Folders -> Cache as "folder" extension
        if Path::new(&path).is_dir() {
            return self
                .get_icon(IconRequest::Extension("folder".to_string()))
                .await;
        }

        // 4. Other files -> Extension based cache via get_icon
        let extension = Path::new(&path)
            .extension()
            .and_then(|ext| ext.to_str())
            .unwrap_or("")
            .to_lowercase();

        if extension.is_empty() {
            return ImageProcessor::load_image(&ImageIdentity::File(path)).await;
        }

        // Use get_icon to handle caching automatically
        self.get_icon(IconRequest::Extension(format!(".{}", extension)))
            .await
    }
}

#[derive(Debug)]
pub struct IconManager {
    inner: RwLock<IconManagerInner>,
}

impl IconManager {
    pub fn new(config: RuntimeIconManagerConfig) -> Self {
        Self {
            inner: RwLock::new(IconManagerInner::new(config)),
        }
    }

    pub async fn load_from_config(&self, config: Arc<IconManagerConfig>) {
        let mut inner = self.inner.write().await;
        inner.load_from_config(config);
    }

    pub async fn get_icon(&self, request: IconRequest) -> Vec<u8> {
        let inner = self.inner.read().await;
        inner.get_icon(request).await
    }

    pub async fn update_program_icon_cache(
        &self,
        icon_request: IconRequest,
        new_icon_source: &str,
    ) -> Result<(), String> {
        let inner = self.inner.read().await;
        if !inner.enable_icon_cache {
            return Err("Icon cache is disabled".to_string());
        }

        // 1. 计算缓存文件名 (Hash)
        let hash_name = icon_request.get_hash_string() + ".png";
        let cached_icon_dir = ICON_CACHE_DIR.clone();
        let target_icon_path = Path::new(&cached_icon_dir).join(&hash_name);

        // 2. 处理新图标源
        // new_icon_source 可能是图片文件，也可能是 exe/lnk
        let identity = ImageIdentity::File(new_icon_source.to_string());
        let mut icon_data = ImageProcessor::load_image(&identity).await;

        if icon_data.is_empty() {
            return Err("Failed to load new icon".to_string());
        }

        // 3. 裁剪透明白边 (保持一致性)
        if let Ok(output) = ImageProcessor::trim_transparent_white_border(icon_data.clone()) {
            icon_data = output;
        }

        // 4. 如果图标过大，则将其等比例的缩小，以提高读取的速度
        if let Ok(resized) = ImageProcessor::resize_image(icon_data.clone(), 256, 256).await {
            icon_data = resized;
        }

        // 5. 覆盖写入缓存
        tokio::fs::write(target_icon_path, icon_data)
            .await
            .map_err(|e| e.to_string())?;

        Ok(())
    }

    pub async fn get_everything_icon(&self, path: String) -> Vec<u8> {
        let inner = self.inner.read().await;
        inner.get_everything_icon(path).await
    }
}
